#include "ShapeData.h"

ShapeData::ShapeData()
{
    fixtureDict = new CCDictionary();
}

ShapeData::~ShapeData()
{
    if (fixtureDict) {
        fixtureDict->release();
        fixtureDict = NULL;
    }
}

void ShapeData::initShapeData(const string &_fileName)
{
    if (fixtureDict->count() > 0) {
        fixtureDict->removeAllObjects();
    }

    fileName = CCFileUtils::sharedFileUtils()->fullPathForFilename(_fileName.c_str());

    xml_document xmlDoc;
    xml_parse_result result;

    unsigned long size = 0;
    unsigned char* pData = 0;
    pData = CCFileUtils::sharedFileUtils()->getFileData(fileName.c_str(), "rb", &size);
    result = xmlDoc.load_buffer(pData, size);
    CC_SAFE_DELETE_ARRAY(pData);

    if (result) {
        xml_node objects = xmlDoc.child(KEY_OBJECTS);
        CCArray *fixtureArray;

        for (xml_node_iterator childNode = objects.begin(); childNode != objects.end(); ++childNode) {
            string name = childNode->attribute(KEY_NAME).value();
            fixtureArray = this->getFixtureList(childNode->child(KEY_FIXTURES));
            fixtureDict->setObject(fixtureArray, name);
            fixtureArray->release();
        }

        // debug
#ifdef CCOBJECT_DEBUG
        CCLOG("xmlfile: %s loaded success!\n", fileName.c_str());
        CCPrettyPrinter visitor;
        fixtureDict->acceptVisitor(visitor);
        CCLog("fixture dict: %s\n", visitor.getResult().c_str());
#endif
    } else {
        CCLOG("load xml error");
    }
}

CCArray* ShapeData::getFixtureList(const xml_node &_fixtureNode)
{
    CCArray *fixtureArray = new CCArray();
    CCArray *vertices;
    CCDictionary *fixDict;
    CCDictionary *attrDict;

    for (xml_node_iterator fixture = _fixtureNode.begin(); fixture != _fixtureNode.end(); ++fixture) {
        fixDict = getAttributeDict(fixture);

        xml_node shapeNode = fixture->child(KEY_SHAPE);
        string shapeType = shapeNode.attribute(KEY_TYPE).value();
        fixDict->setObject(CCString::create(shapeType), KEY_SHAPE);

        // add polygon shape
        if (shapeType.compare(KEY_POLYGON) == 0) {
            vertices = new CCArray(MAX_VERTICES);

            xml_node verticesNode = shapeNode.child(KEY_VERTICES);
            for (xml_node_iterator position = verticesNode.begin(); position != verticesNode.end(); ++position) {
                attrDict = getAttributeDict(position);
                vertices->addObject(attrDict);
                attrDict->release();
            }
            fixDict->setObject(vertices, KEY_VERTICES);
            vertices->release();
        }
        // add circle shape
        else if (shapeType.compare(KEY_CIRCLE) == 0) {
            // set center
            attrDict = getAttributeDict(shapeNode.child(KEY_POSITION));
            fixDict->setObject(attrDict, KEY_POSITION);
            attrDict->release();

            // set radius
            fixDict->setObject(CCString::create(shapeNode.child(KEY_RADIUS).first_child().value()), KEY_RADIUS);
        }
        fixtureArray->addObject(fixDict);
        fixDict->release();
    }

    // debug
#ifdef CCOBJECT_DEBUG
    CCPrettyPrinter visitor;
    fixtureArray->acceptVisitor(visitor);
    CCLog("fixtures array:\n %s \n", visitor.getResult().c_str());
#endif
    return fixtureArray;
}

void ShapeData::createFixtures(b2Body *_body, const string &_key, const char &_filterGroup)
{
    CCArray *fixtArray = (CCArray*)fixtureDict->objectForKey(_key);
    CCDictionary *fixtDict;
    CCArray *tempArray;
    CCDictionary *posDict;
    b2Vec2 *vertices;

#ifdef CCOBJECT_DEBUG
    CCPrettyPrinter printer;
    fixtArray->acceptVisitor(printer);
    CCLog("fixtures array: %s", printer.getResult().c_str());
#endif

    CCObject *child;
    CCARRAY_FOREACH(fixtArray, child) {
        fixtDict = (CCDictionary*)child;

        b2FixtureDef fixtDef;
        b2PolygonShape polyShape;
        b2CircleShape circleShape;
        // get polygon shape
        if (fixtDict->valueForKey(KEY_SHAPE)->compare(KEY_POLYGON) == 0) {

            tempArray = (CCArray*)fixtDict->objectForKey(KEY_VERTICES);
            // get vertices
            vertices = new b2Vec2[tempArray->count()]();
            for (unsigned int i = 0; i < tempArray->count(); ++i) {
                posDict = (CCDictionary*)tempArray->objectAtIndex(i);
                vertices[i] = getPosFromDict(posDict);
            }
            polyShape.Set(vertices, tempArray->count());
            fixtDef.shape = &polyShape;
            if (vertices) {
                delete vertices;
                vertices = NULL;
            }
        }
        // get circle shape
        else if (fixtDict->valueForKey(KEY_SHAPE)->compare(KEY_CIRCLE) == 0) {            
            posDict = (CCDictionary*)fixtDict->objectForKey(KEY_POSITION);
            // get center
            circleShape.m_p = getPosFromDict(posDict);
            // get radius
            circleShape.m_radius = getRadiusFromDict(fixtDict);
            fixtDef.shape = &circleShape;
        }

        // get attributes
        fixtDef.friction = fixtDict->valueForKey(KEY_FRICTION)->floatValue();
        fixtDef.restitution = fixtDict->valueForKey(KEY_RESTITUTION)->floatValue();
        fixtDef.density = fixtDict->valueForKey(KEY_DENSITY)->floatValue();
        fixtDef.userData = fixtDict->objectForKey(KEY_USERDATA);

        // check if sensor
        if (fixtDict->valueForKey(KEY_SENSOR)->boolValue()) {
            fixtDef.isSensor = true;
        }

        // filter group
        if (_filterGroup != 0) {
            fixtDef.filter.groupIndex = _filterGroup;
        }

        // create fixture for body
        _body->CreateFixture(&fixtDef);
    }
}
